home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 2000 August: Tool Chest / Dev.CD Aug 00 TC Disk 2.toast / pc / sample code / quicktime / goodies / jpeg file interchange format / jfif preview component / jfifpreviewer.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-06-23  |  17.7 KB  |  707 lines

  1. /*
  2.     File:        JFIFPreviewer.c
  3.  
  4.     Contains:    
  5.  
  6.     Written by:     
  7.  
  8.     Copyright:    Copyright © 1984-1999 by Apple Computer, Inc., All Rights Reserved.
  9.  
  10.                 You may incorporate this Apple sample source code into your program(s) without
  11.                 restriction. This Apple sample source code has been provided "AS IS" and the
  12.                 responsibility for its operation is yours. You are not permitted to redistribute
  13.                 this Apple sample source code as "Apple sample source code" after having made
  14.                 changes. If you're going to re-distribute the source, we require that you make
  15.                 it clear in the source that the code was descended from Apple sample source
  16.                 code, but that you've made changes.
  17.  
  18.     Change History (most recent first):
  19.                 8/16/1999    Karl Groethe    Updated for Metrowerks Codewarror Pro 2.1
  20.                 
  21.  
  22. */
  23.  
  24. #include <Aliases.h>
  25. #include <Files.h>
  26. #include <Errors.h>
  27. #include <ToolUtils.h>
  28. #include <Memory.h>
  29. #include <QDOffscreen.h>
  30. #include <Components.h>
  31. #include <ImageCompression.h>
  32. #include <QuicktimeComponents.h>
  33. #include <FixMath.h>
  34.  
  35. enum{
  36.         uppCanDoSelectorProcInfo=kPascalStackBased
  37.          | RESULT_SIZE(SIZE_CODE(sizeof(ComponentResult)))
  38.          | STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(short))),
  39.          uppshowJFIFPreviewProcInfo=kPascalStackBased
  40.          | RESULT_SIZE(SIZE_CODE(sizeof(ComponentResult)))
  41.          | STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(OSType)))
  42.          | STACK_ROUTINE_PARAMETER(2, SIZE_CODE(sizeof(PicHandle)))
  43.          | STACK_ROUTINE_PARAMETER(3, SIZE_CODE(sizeof(Rect*))),
  44.          uppmakeJFIFPreviewProcInfo=kPascalStackBased
  45.          | RESULT_SIZE(SIZE_CODE(sizeof(ComponentResult)))
  46.          | STACK_ROUTINE_PARAMETER(1,SIZE_CODE(sizeof(OSType*)))
  47.          | STACK_ROUTINE_PARAMETER(2,SIZE_CODE(sizeof(Handle*)))
  48.          | STACK_ROUTINE_PARAMETER(3,SIZE_CODE(sizeof(const FSSpec*)))
  49.          | STACK_ROUTINE_PARAMETER(4,SIZE_CODE(sizeof(ICMProgressProcRecordPtr)))
  50. };
  51. pascal ComponentResult PreviewShowData(pnotComponent p, OSType dataType, Handle data,
  52.         const Rect *inHere)
  53. {
  54.     #pragma unused(p,dataType,data,inHere)
  55.     ComponentCallNow(1, 12);
  56.     return 0;
  57. }
  58.  
  59.  
  60. /*
  61.  
  62.     NOTE: to install this previewer ( or any other components ) inside your application:
  63.     
  64.     put all the resources into your app then do this:
  65.     
  66.     {
  67.         Handle h;
  68.         short i,c;
  69.         short myAppFile;            // the res file refnum of your app = current res file at launch
  70.         Boolean everyBody = false;    // set to true to let other apps use component 
  71.         
  72.         UseResFile(myAppFile);
  73.         c = Count1Resources('thng');
  74.         for ( i=1; i <= c; i++ )
  75.             h = Get1IndResource('thng',i);
  76.             RegisterComponentResource((ComponentResourceHandle)h,everyBody);
  77.             ReleaseResource(h);
  78.         }
  79.     }
  80.     
  81. */
  82.  
  83.  
  84. #define    DEFAULT_COMPRESSION        'rpza'                // compressor for created previews - zero for uncompressed
  85. #define    DEFAULT_QUALITY            codecHighQuality    // quality level for created previews
  86.  
  87. #define    SBSIZE                    2048            // size of scan buffer for scanning for JFIF header
  88.  
  89.  
  90. /***********
  91.  
  92.     struct for deep progressProc.
  93.     
  94. ***********/
  95.  
  96. typedef     struct {
  97.     ICMProgressProcRecordPtr    progress;
  98.     GDHandle    gd;
  99.     CGrafPtr    port;
  100.     Fixed    start,end;
  101. } adpRec;
  102.  
  103. /***********
  104.  
  105.     struct for spooling with dataProcs.
  106.     
  107. ***********/
  108.  
  109. typedef    struct {
  110.     Ptr        bufEnd;
  111.     Ptr        bufStart;
  112.     long    bufSize;
  113.     long    size;
  114.     short    refNum;
  115. } DPRec;
  116.  
  117.  
  118. /***********
  119.     
  120.     function prototypes
  121.     
  122. **********/
  123.  
  124. pascal ComponentResult JFIFPreviewDispatch( ComponentParameters *params, Handle storage );
  125. pascal ComponentResult showJFIFPreview(OSType dataType, PicHandle data, const Rect *inHere);
  126. pascal ComponentResult makeJFIFPreview(OSType *previewType, Handle *previewResult,
  127.                     const FSSpec *sourceFile, ICMProgressProcRecordPtr progress);
  128. pascal ComponentResult    CanDoSelector(short selector);
  129. pascal OSErr    adpProc(short msg,Fixed pct,long refcon);
  130. pascal OSErr    dataProc(Ptr *cp,long sizeNeeded,long refcon);
  131. OSErr    ReadJFIFThumbnail(short refNum, Handle *thumbnail, ICMProgressProcRecordPtr progress, Boolean thumbOnly);
  132.  
  133.  
  134. /***************************************************
  135.  
  136.     Component entry point.
  137.  
  138. ***************************************************/
  139. #ifdef powerc
  140. ProcInfoType __procinfo=kPascalStackBased
  141.          | RESULT_SIZE(SIZE_CODE(sizeof(ComponentResult)))
  142.          | STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(ComponentParameters*)))
  143.          | STACK_ROUTINE_PARAMETER(2, SIZE_CODE(sizeof(Handle)));
  144. #endif
  145. pascal ComponentResult JFIFPreviewDispatch( ComponentParameters *params, Handle storage )
  146. {
  147. #pragma unused(storage)
  148.     ComponentFunctionUPP    componentProc = 0;
  149.     ComponentResult err = 0;
  150.  
  151.     switch (params->what) {
  152.         case kComponentOpenSelect:
  153. #ifdef THINK_C
  154.             SetComponentInstanceA5((ComponentInstance)params->params[0], *(long *)CurrentA5);
  155. #endif    
  156.             break;
  157.         case kComponentCloseSelect:
  158.             break;
  159.         case kComponentCanDoSelect:
  160.             return CallComponentFunction(params,NewRoutineDescriptor((ProcPtr)CanDoSelector, uppCanDoSelectorProcInfo, GetCurrentArchitecture()));    
  161.             break;
  162.         case kComponentVersionSelect:
  163.             return 0;
  164.             break;
  165.         case 1:    
  166.             componentProc = NewRoutineDescriptor((ProcPtr)showJFIFPreview,uppshowJFIFPreviewProcInfo,GetCurrentArchitecture());
  167.             break;
  168.         case 2: 
  169.             componentProc = NewRoutineDescriptor((ProcPtr)makeJFIFPreview,uppmakeJFIFPreviewProcInfo,GetCurrentArchitecture());
  170.             break;
  171.     }
  172.  
  173.     if (componentProc)
  174.         err = CallComponentFunction(params, componentProc);
  175.  
  176.     return err;
  177. }
  178.  
  179. /***************************************************
  180.  
  181.     Indicate whether we can handle the call or not.
  182.     
  183. ***************************************************/
  184.  
  185. pascal ComponentResult
  186. CanDoSelector(short selector)
  187. {    
  188.     switch (selector) {
  189.     case kComponentOpenSelect:
  190.     case kComponentCloseSelect:
  191.     case kComponentCanDoSelect:
  192.     case kComponentVersionSelect: 
  193.     case 1:
  194.     case 2:
  195.         return(true);
  196.     default:
  197.         return (false);
  198.     }
  199. }
  200.  
  201. /***************************************************
  202.  
  203.     We are asked to make a thumbnail from a JFIF file. We comply.
  204.  
  205. ***************************************************/
  206.     
  207.  
  208. pascal ComponentResult makeJFIFPreview(OSType *previewType, Handle *previewResult,
  209.                     const FSSpec *sourceFile, ICMProgressProcRecordPtr progress)
  210. {
  211.     OSErr err;
  212.     Handle thumbnail = 0;
  213.     short refNum;
  214.  
  215.     err = FSpOpenDF(sourceFile, fsRdPerm, &refNum);
  216.     *previewResult = nil;
  217.     if (!err) {
  218.         err = ReadJFIFThumbnail(refNum, previewResult, progress, false);
  219.         FSClose(refNum);
  220.     }
  221.  
  222. bail:
  223.     if (!err) {
  224.         *previewType = 'PICT';
  225.     } else if ( *previewResult ) {
  226.         DisposeHandle(*previewResult);
  227.         *previewResult = nil;
  228.     }
  229.     return(err);
  230. }
  231.  
  232.  
  233. /***************************************************
  234.  
  235.     Called to show the preview. Data is a picture, type is 'PICT';
  236.     
  237. ***************************************************/
  238.  
  239. pascal ComponentResult showJFIFPreview(OSType dataType, PicHandle data, const Rect *inHere)
  240. {
  241.     OSErr err = noErr;
  242.     Handle thumbnail = 0;
  243.     short refNum;
  244.     FSSpec theFile;
  245.     Boolean whoCares;
  246.     Handle thePict = nil;
  247.     ComponentInstance ci;
  248.  
  249.     if (dataType != rAliasType)
  250.         return paramErr;
  251.  
  252.     if (err = ResolveAlias(nil, (AliasHandle)data, &theFile, &whoCares)) goto bail;
  253.  
  254.     err = FSpOpenDF(&theFile, fsRdPerm, &refNum);
  255.     if (!err) {
  256.         err = ReadJFIFThumbnail(refNum, &thePict, nil, true);
  257.         FSClose(refNum);
  258.     }
  259.     if (err) goto bail;
  260.  
  261.     if (ci = OpenDefaultComponent('pnot', 'PICT')) {
  262.         PreviewShowData(ci, 'PICT', thePict, inHere);
  263.         CloseComponent(ci);
  264.     }
  265.  
  266.     KillPicture((PicHandle)thePict);
  267.  
  268. bail:
  269.     return err;
  270. }
  271.  
  272.  
  273.  
  274. /***************************************************
  275.  
  276.     This does the work. It checks for a JFIF thumbnail and if there is one,
  277.     it makes a PICT out of it. If not it draws the JFIF file into a 96x96 (max)
  278.     offscreen and makes a PICT out of that.
  279.  
  280. ***************************************************/
  281.  
  282. OSErr
  283. ReadJFIFThumbnail(short refNum, Handle *thumbnail, ICMProgressProcRecordPtr progress, Boolean thumbOnly)
  284.  
  285. {
  286.     long    refcon = 0;
  287.  
  288.     unsigned char buf[SBSIZE];
  289.     long l = SBSIZE;
  290.     short i;
  291.     short    j,w = 0,h = 0;
  292.     Rect    frame;
  293.     PicHandle pict = nil;
  294.     GWorldPtr    gw = nil;
  295.     CGrafPtr savePort;
  296.     GDHandle    saveGD;
  297.     unsigned char *bp,*rp;
  298.     short    rb;
  299.     char    mmuMode = 1;
  300.     char    oldMMUMode;
  301.     short x,y;
  302.     Ptr        tp;
  303.     short     err = 0;
  304.     short    numCom = 0;
  305.     short    hv1 =0,hv2=0,hv3=0;
  306.     
  307.     /* call the progress proc if we have to. */
  308.     
  309.     if ( progress)  {
  310.         if ( CallICMProgressProc(progress->progressProc,codecProgressOpen,0,progress->progressRefCon) ) {
  311.             err = -1;
  312.             goto done;
  313.         }
  314.         if ( CallICMProgressProc(progress->progressProc,codecProgressUpdatePercent,0x1,progress->progressRefCon) ) {
  315.             err = -1;
  316.             goto done;
  317.         }
  318.     }
  319.     
  320.     GetGWorld(&savePort,&saveGD);
  321.     FSRead(refNum,&l,(Ptr)buf);
  322.     
  323.     /* scan the JFIF stream for a JFIF header, or a SOF header */
  324.     
  325.     for ( i=0; i < SBSIZE; i++ ) {
  326.         if ( buf[i] == 0xff ) {
  327.             i++;
  328.             
  329.             /* JFIF header */
  330.             
  331.             if ( buf[i] == (unsigned char)0xe0 ) {
  332.                 i++;
  333.                 j = (buf[i] << 8) | buf[i+1];
  334.                 i++;
  335.                 if ( j <= 16 )                    /* no thumbnail - keep scanning */
  336.                     continue;
  337.                 if ( buf[i+1] == 'J'  &&
  338.                     buf[i+2] == 'F'  &&
  339.                     buf[i+3] == 'I'  &&
  340.                     buf[i+4] == 'F' &&
  341.                     buf[i+5] == 0 &&
  342.                     buf[i+6] == 1 &&
  343.                     buf[i+7] <= 1 ) {
  344.                     w = buf[i+13];
  345.                     h = buf[i+14];
  346.                     if ( w == 0 || h == 0 )        /* no thumbnail - keep scanning */
  347.                         continue;
  348.                     else {
  349.                     
  350.                         /* read in the thumbnail - its 8-8-8 rgb for w*h pixels */
  351.                         
  352.                         l = w*h*3;
  353.                         SetFPos(refNum,fsFromStart,(long)i+15);
  354.                         i = 0;
  355.                         tp = NewPtr(l);
  356.                         if ( tp == nil ) {
  357.                             err = -108;
  358.                             goto done;
  359.                         }
  360.                         if ( progress)  {
  361.                             if ( CallICMProgressProc(progress->progressProc,codecProgressUpdatePercent,0x0100,progress->progressRefCon) ) {
  362.                                 err = -1;
  363.                                 goto done;
  364.                             }
  365.                         }
  366.                         FSRead(refNum,&l,tp);
  367.                         SetRect(&frame,0,0,w,h);
  368.                         
  369.                         /* make a 16-bit gworld and copy the thumbnail into it */
  370.                         
  371.                         if ( NewGWorld(&gw,16,&frame,nil,nil,0) == 0 || 
  372.                              NewGWorld(&gw,16,&frame,nil,nil,8) == 0 ) {
  373.                             LockPixels(gw->portPixMap);
  374.                             bp = (unsigned char *)GetPixBaseAddr(gw->portPixMap);
  375.                             rb = (*gw->portPixMap)->rowBytes & 0x3fff;
  376.                             oldMMUMode = GetMMUMode();
  377.                             SwapMMUMode(&mmuMode);
  378.                             for ( y=0; y < h; y++ ) {
  379.                                 rp = bp;
  380.                                 if ( progress) { 
  381.                                     SwapMMUMode(&oldMMUMode);
  382.                                     if ( CallICMProgressProc(progress->progressProc,codecProgressUpdatePercent,0x1000 + (0x9000  * y) / h,progress->progressRefCon) ) {
  383.                                         err = -1;
  384.                                         goto done;
  385.                                     }
  386.                                     SwapMMUMode(&oldMMUMode);
  387.                                 }
  388.                                 for ( x=0; x < w; x++ ) {
  389.                                     short pix = (0x1f & (tp[i++]>>3)) << 10;
  390.                                     pix |= (0x1f & (tp[i++]>>3)) << 5;
  391.                                     pix |= (0x1f & (tp[i++]>>3));
  392.                                     *(short *)rp = pix;
  393.                                     rp += 2;
  394.                                 }
  395.                                 bp += rb;
  396.                             }
  397.                             SwapMMUMode(&mmuMode);
  398.                             DisposePtr(tp);
  399.                             break;            /* okay we got it - get outof the scan loop */
  400.                         } else {
  401.                             err = -108;
  402.                             goto done;
  403.                         }
  404.                     }
  405.                 } else {
  406.                     err = -108;        // no memory
  407.                     goto done;
  408.                 }
  409.                 
  410.                 /* start of frame header - grab the width and height */
  411.                 
  412.             } else if ( buf[i] == (unsigned char)0xc0 ) {
  413.                 i += 4;
  414.                 h = (buf[i]<<8) | buf[i+1];
  415.                 i += 2;
  416.                 w = (buf[i]<<8) | buf[i+1];
  417.                 i += 2;
  418.                 numCom = buf[i];
  419.                 if ( numCom == 3 ) {
  420.                     i += 2;
  421.                     hv1 = buf[i];
  422.                     i += 3;
  423.                     hv2 = buf[i];
  424.                     i += 3;
  425.                     hv3 = buf[i];
  426.                 }    
  427.                 break;
  428.             }
  429.         }
  430.     }
  431.     /* couldn't find a SOF header - so bail */
  432.     
  433.     if ( w == 0 || h == 0 ) {
  434.         err = -50;
  435.         goto done;
  436.     }
  437.     
  438.     /* there was no thumbnail - so draw the whole image */
  439.     
  440.     if ( gw == nil ) {
  441.         ImageDescriptionHandle desc = nil;
  442.         ICMDataProcRecord dataP,*dataPP = nil;
  443.         DPRec dataRec;
  444.         ICMProgressProcRecord pproc;
  445.         adpRec adpRec;
  446.         MatrixRecord matrix;
  447.         short    tw,th;
  448.         Rect    tframe;
  449.         Ptr    buffer = nil;
  450.         
  451.         if (thumbOnly) {
  452.             err = -50;
  453.             goto done;
  454.         }
  455.  
  456.         if ( (desc = (ImageDescriptionHandle)NewHandle(sizeof(ImageDescription))) == nil ) {
  457.             err = MemError();
  458.             goto cbail;
  459.         }
  460.         /* make up an image description */
  461.         
  462.         (*desc)->idSize = sizeof(ImageDescription);
  463.         (*desc)->temporalQuality = 0;
  464.         (*desc)->spatialQuality = codecNormalQuality;
  465.         (*desc)->dataSize = l;
  466.         (*desc)->cType = 'jpeg';
  467.         (*desc)->version = 0;
  468.         (*desc)->revisionLevel = 0;
  469.         (*desc)->vendor = 0;
  470.         (*desc)->hRes = 72L<<16;
  471.         (*desc)->vRes = 72L<<16;
  472.         (*desc)->width = w;
  473.         (*desc)->height = h;
  474.         (*desc)->depth = 32;
  475.         (*desc)->clutID = -1;
  476.         BlockMove("\pPhoto - JPEG",(*desc)->name,13);
  477.         
  478.         if ( w > h ) {
  479.             tw = 96;
  480.             th = h * 96 / w ;
  481.         } else {
  482.             th = 96;
  483.             tw = w * 96 / h ;
  484.         }
  485.         SetRect(&tframe,0,0,tw,th);
  486.         SetRect(&frame,0,0,w,h);
  487.         
  488.         /* make a gworld up to 96x96 pixels and draw the JFIF file in it */
  489.         
  490.         if ( NewGWorld(&gw,16,&tframe,nil,nil,0) == 0 || 
  491.              NewGWorld(&gw,16,&tframe,nil,nil,8) == 0 ) {
  492.              
  493.              
  494.             if ( progress ) {
  495.             
  496.                 /* make a progressproc to call for partial progress */
  497.                 
  498.                 adpRec.progress = progress;
  499.                 adpRec.port = savePort;
  500.                 adpRec.gd = saveGD;
  501.                 adpRec.start = 0x1000;
  502.                 adpRec.end = 0xa000;
  503.                 
  504.                 pproc.progressProc = NewICMProgressProc(adpProc);
  505.                 pproc.progressRefCon = (long)&adpRec;
  506.                 if ( CallICMProgressProc(progress->progressProc,codecProgressUpdatePercent,0x0100,progress->progressRefCon) ) {
  507.                     err = -1;
  508.                     goto cbail;
  509.                 }
  510.             }
  511.             
  512.             /* read in file */
  513.             
  514.             GetEOF(refNum,&l);
  515.             if ( (buffer = NewPtr(l)) == nil ) {
  516.             
  517.             
  518.                 /* if we cant fit the whole thing in memory - make a dataProc to spool it in */
  519.                 
  520.                 if ( (buffer= NewPtr(codecMinimumDataSize)) == nil ) {
  521.                     err = MemError();
  522.                     goto cbail;
  523.                 }
  524.                 dataRec.refNum = refNum;
  525.                 dataRec.bufStart = buffer;
  526.                 dataRec.bufEnd = buffer + codecMinimumDataSize;
  527.                 dataRec.size = l - codecMinimumDataSize;
  528.                 dataRec.bufSize = codecMinimumDataSize;
  529.                 dataPP = &dataP;
  530.                 dataP.dataRefCon = (long)&dataRec;
  531.                 dataP.dataProc = NewICMDataProc(dataProc);
  532.                 l = codecMinimumDataSize;
  533.             }
  534.             if ( progress ) {
  535.                 if ( CallICMProgressProc(progress->progressProc,codecProgressUpdatePercent,0x0800,progress->progressRefCon) ) {
  536.                     err = -1;
  537.                     goto cbail;
  538.                 }
  539.             }
  540.             SetFPos(refNum,fsFromStart,0);
  541.             if ( (err=FSRead(refNum,&l,buffer)) != 0 ) 
  542.                 goto cbail;
  543.             if ( progress ) {
  544.                 if ( CallICMProgressProc(progress->progressProc,codecProgressUpdatePercent,0x1000,progress->progressRefCon) ) {
  545.                     err = -1;
  546.                     goto cbail;
  547.                 }
  548.             }
  549.             RectMatrix(&matrix,&frame,&tframe);
  550.             SetGWorld(gw,nil);
  551.             err=FDecompressImage(buffer,desc,gw->portPixMap,
  552.                         &frame,&matrix,ditherCopy,(RgnHandle)nil,
  553.                         (PixMapHandle)nil,(Rect *)nil,codecHighQuality,anyCodec,0,
  554.                         dataPP,progress ?  &pproc : nil);
  555.             frame = tframe;
  556. cbail:
  557.             SetGWorld(savePort,saveGD);
  558.             if ( buffer )
  559.                 DisposePtr(buffer);
  560.             if ( desc )
  561.                 DisposeHandle((Handle)desc);
  562.             if ( err )    
  563.                 goto done;
  564.         } else {
  565.             err = -108;
  566.             goto done;
  567.         }
  568.     }
  569.  
  570.     /* if we get here than gw holds the image for the thumbnail - put it in a PICT and compress it */
  571.  
  572.     if ( gw ) {
  573.         if ( progress)  {
  574.             if ( CallICMProgressProc(progress->progressProc,codecProgressUpdatePercent,0xa000,progress->progressRefCon) ) {
  575.                 err = -1;
  576.                 goto done;
  577.             }
  578.         }
  579.         SetGWorld(gw,nil);
  580.         pict = OpenPicture(&frame);
  581.         ClipRect(&frame);
  582.         EraseRect(&frame);
  583.         CopyBits((BitMap *)*gw->portPixMap,(BitMap *)*gw->portPixMap,
  584.             &gw->portRect,&gw->portRect,ditherCopy,nil);
  585.         ClosePicture();
  586.         SetGWorld(savePort,saveGD);
  587.         if (thumbOnly) {
  588.             *thumbnail = (Handle)pict;
  589.             goto done;
  590.         }
  591.  
  592.         if ( progress)  {
  593.             if ( CallICMProgressProc(progress->progressProc,codecProgressUpdatePercent,0xb000,progress->progressRefCon) ) {
  594.                 err = -1;
  595.                 goto done;
  596.             }
  597.         }
  598.         DisposeGWorld(gw);
  599.         gw  = nil;
  600.         if ( GetHandleSize((Handle)pict) <= sizeof(Picture) ) {
  601.             DisposeHandle((Handle)pict);
  602.             err = -108;                // no memory
  603.         } else {
  604.             *thumbnail = NewHandle(sizeof(Picture));
  605.             if ( progress) {
  606.                 if ( CallICMProgressProc(progress->progressProc,codecProgressUpdatePercent,0xc000,progress->progressRefCon) ) {
  607.                     err = -1;
  608.                     goto done;
  609.                 }
  610.             }
  611.             if ( DEFAULT_COMPRESSION != 0 ) {
  612.                 if ( (err=CompressPicture(pict,(PicHandle)*thumbnail,DEFAULT_QUALITY,DEFAULT_COMPRESSION)) != 0 ) {
  613.                     DisposeHandle(*thumbnail);
  614.                     *thumbnail = nil;
  615.                     DisposeHandle((Handle)pict);
  616.                     goto done;
  617.                 }
  618.                 DisposeHandle((Handle)pict);
  619.             } else {
  620.                 *thumbnail = (Handle)pict;
  621.             }
  622.             if ( progress) 
  623.                 CallICMProgressProc(progress->progressProc,codecProgressUpdatePercent,0x10000,progress->progressRefCon);
  624.         }
  625.     }
  626. done:
  627.     if ( gw )
  628.         DisposeGWorld(gw);
  629.     SetGWorld(savePort,saveGD);
  630.     if ( progress) 
  631.         CallICMProgressProc(progress->progressProc,codecProgressClose,0,progress->progressRefCon);
  632.     return(err);
  633. }
  634.  
  635.  
  636.  
  637. /***************************************************
  638.  
  639.     Deep progressproc - scales calls from proc and passes them up to higher level.
  640.     
  641. ***************************************************/
  642.  
  643. pascal OSErr
  644. adpProc(short msg,Fixed pct,long refcon) 
  645. {
  646.     OSErr    res = 0;
  647.     CGrafPtr savePort;
  648.     GDHandle    saveGD;
  649.     adpRec *adpr = (adpRec *)refcon;
  650.     
  651.     if ( msg == codecProgressUpdatePercent ) {
  652.         pct = adpr->start + FixMul(pct,adpr->end-adpr->start);
  653.         GetGWorld(&savePort,&saveGD);
  654.         SetGWorld(adpr->port,adpr->gd);
  655.         res = CallICMProgressProc(adpr->progress->progressProc,msg,pct,adpr->progress->progressRefCon);
  656.         SetGWorld(savePort,saveGD);
  657.     }
  658.     return(res);
  659. }
  660.  
  661. /***************************************************
  662.  
  663.     DataProc for spooling in compressed data.
  664.     
  665. ***************************************************/
  666.  
  667. pascal OSErr
  668. dataProc(Ptr *cp,long sizeNeeded,long refcon)
  669. {
  670.     char     mode = 0;
  671.     Ptr        current;
  672.     long    newChunk;
  673.     long    leftOver;
  674.     long    size;
  675.     OSErr     result = noErr;
  676.     DPRec     *dpr = (DPRec *)refcon;
  677.     
  678.  
  679.     if ( cp == nil ) 
  680.         return(-1);            /* dont do random access yet */
  681.         
  682.     current = *cp;
  683.     SwapMMUMode(&mode);
  684.     if ( (current + sizeNeeded) > dpr->bufEnd )  {
  685.     
  686.         // move whats left up to the front of the buffer
  687.         
  688.         leftOver = dpr->bufEnd - current;
  689.         BlockMove(current,dpr->bufStart,leftOver);        
  690.         newChunk = dpr->bufSize - leftOver;
  691.         if ( dpr->size < newChunk )
  692.             newChunk = dpr->size;
  693.         if ( newChunk ) {
  694.             size = newChunk;
  695.             FSRead(dpr->refNum,&size,dpr->bufStart+leftOver);
  696.             dpr->size -= newChunk;
  697.             dpr->bufEnd = dpr->bufStart+leftOver+newChunk;
  698.         }
  699.         *cp = dpr->bufStart;
  700.     }
  701.     SwapMMUMode(&mode);
  702.     return(result);
  703. }
  704.  
  705.  
  706.  
  707.